home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / glibc108.zip / glibc108 / sysdeps / posix / getcwd.c < prev    next >
C/C++ Source or Header  |  1993-05-07  |  8KB  |  368 lines

  1. /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. /* Wants:
  20.    AC_STDC_HEADERS
  21.    AC_DIR_HEADER
  22.    AC_UNISTD_H
  23.    AC_MEMORY_H
  24.    AC_CONST
  25.    AC_ALLOCA
  26.  */
  27.  
  28. /* AIX requires this to be the first thing in the file.  */
  29. #if defined (_AIX) && !defined (__GNUC__)
  30.  #pragma alloca
  31. #endif
  32.  
  33. #ifdef    HAVE_CONFIG_H
  34. #include "config.h"
  35. #endif
  36.  
  37. #include <errno.h>
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40.  
  41. #ifdef    STDC_HEADERS
  42. #include <stddef.h>
  43. #endif
  44.  
  45. #if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
  46. extern int errno;
  47. #endif
  48.  
  49. #ifndef    NULL
  50. #define    NULL    0
  51. #endif
  52.  
  53. #if defined (USGr3) && !defined (DIRENT)
  54. #define DIRENT
  55. #endif /* USGr3 */
  56. #if defined (Xenix) && !defined (SYSNDIR)
  57. #define SYSNDIR
  58. #endif /* Xenix */
  59.  
  60. #if defined (POSIX) || defined (DIRENT) || defined (__GNU_LIBRARY__)
  61. #include <dirent.h>
  62. #ifndef    __GNU_LIBRARY__
  63. #define D_NAMLEN(d) strlen((d)->d_name)
  64. #else
  65. #define    HAVE_D_NAMLEN
  66. #define D_NAMLEN(d) ((d)->d_namlen)
  67. #endif
  68. #else /* not POSIX or DIRENT */
  69. #define    dirent        direct
  70. #define D_NAMLEN(d)    ((d)->d_namlen)
  71. #define    HAVE_D_NAMLEN
  72. #if defined (USG) && !defined (sgi)
  73. #if defined (SYSNDIR)
  74. #include <sys/ndir.h>
  75. #else /* Not SYSNDIR */
  76. #include "ndir.h"
  77. #endif /* SYSNDIR */
  78. #else /* not USG */
  79. #include <sys/dir.h>
  80. #endif /* USG */
  81. #endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
  82.  
  83. #ifdef    HAVE_UNISTD_H
  84. #include <unistd.h>
  85. #endif
  86.  
  87. #if    (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) \
  88.      || defined (POSIX))
  89. #include <stdlib.h>
  90. #include <string.h>
  91. #define    ANSI_STRING
  92. #else    /* No standard headers.  */
  93.  
  94. #ifdef    USG
  95.  
  96. #include <string.h>
  97. #ifdef    NEED_MEMORY_H
  98. #include <memory.h>
  99. #endif
  100. #define    ANSI_STRING
  101.  
  102. #else    /* Not USG.  */
  103.  
  104. #ifdef    NeXT
  105.  
  106. #include <string.h>
  107.  
  108. #else    /* Not NeXT.  */
  109.  
  110. #include <strings.h>
  111.  
  112. #ifndef    bcmp
  113. extern int bcmp ();
  114. #endif
  115. #ifndef    bzero
  116. extern void bzero ();
  117. #endif
  118. #ifndef    bcopy
  119. extern void bcopy ();
  120. #endif
  121.  
  122. #endif    /* NeXT. */
  123.  
  124. #endif    /* USG.  */
  125.  
  126. extern char *malloc (), *realloc ();
  127. extern void free ();
  128.  
  129. #endif /* Standard headers.  */
  130.  
  131. #ifndef    ANSI_STRING
  132. #define    memcpy(d, s, n)    bcopy((s), (d), (n))
  133. #define    memmove memcpy
  134. #endif    /* Not ANSI_STRING.  */
  135.  
  136. #if    !defined(__alloca) && !defined(__GNU_LIBRARY__)
  137.  
  138. #ifdef    __GNUC__
  139. #undef    alloca
  140. #define    alloca(n)    __builtin_alloca (n)
  141. #else    /* Not GCC.  */
  142. #if    defined (sparc) || defined (HAVE_ALLOCA_H)
  143. #include <alloca.h>
  144. #else    /* Not sparc or HAVE_ALLOCA_H.  */
  145. #ifndef    _AIX
  146. extern char *alloca ();
  147. #endif    /* Not _AIX.  */
  148. #endif    /* sparc or HAVE_ALLOCA_H.  */
  149. #endif    /* GCC.  */
  150.  
  151. #define    __alloca    alloca
  152.  
  153. #endif
  154.  
  155. #if (defined (HAVE_LIMITS_H) || defined (STDC_HEADERS) || \
  156.      defined (__GNU_LIBRARY__))
  157. #include <limits.h>
  158. #else
  159. #include <sys/param.h>
  160. #endif
  161.  
  162. #ifndef PATH_MAX
  163. #ifdef    MAXPATHLEN
  164. #define    PATH_MAX MAXPATHLEN
  165. #else
  166. #define    PATH_MAX 1024
  167. #endif
  168. #endif
  169.  
  170. #ifndef    STDC_HEADERS
  171. #undef    size_t
  172. #define    size_t    unsigned int
  173. #endif
  174.  
  175. #if !__STDC__ && !defined (const)
  176. #define const
  177. #endif
  178.  
  179. #ifndef __GNU_LIBRARY__
  180. #define    __lstat    stat
  181. #define
  182. #endif
  183.  
  184. /* Get the pathname of the current working directory, and put it in SIZE
  185.    bytes of BUF.  Returns NULL if the directory couldn't be determined or
  186.    SIZE was too small.  If successful, returns BUF.  In GNU, if BUF is
  187.    NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
  188.    unless SIZE <= 0, in which case it is as big as necessary.  */
  189.  
  190. char *
  191. getcwd (buf, size)
  192.      char *buf;
  193.      size_t size;
  194. {
  195.   static const char dots[]
  196.     = "../../../../../../../../../../../../../../../../../../../../../../../\
  197. ../../../../../../../../../../../../../../../../../../../../../../../../../../\
  198. ../../../../../../../../../../../../../../../../../../../../../../../../../..";
  199.   const char *dotp, *dotlist;
  200.   size_t dotsize;
  201.   dev_t rootdev, thisdev;
  202.   ino_t rootino, thisino;
  203.   char *path;
  204.   register char *pathp;
  205.   struct stat st;
  206.  
  207.   if (size == 0)
  208.     {
  209.       if (buf != NULL)
  210.     {
  211.       errno = EINVAL;
  212.       return NULL;
  213.     }
  214.  
  215.       size = PATH_MAX + 1;
  216.     }
  217.  
  218.   if (buf != NULL)
  219.     path = buf;
  220.   else
  221.     {
  222.       path = malloc (size);
  223.       if (path == NULL)
  224.     return NULL;
  225.     }
  226.  
  227.   pathp = path + size;
  228.   *--pathp = '\0';
  229.  
  230.   if (__lstat (".", &st) < 0)
  231.     return NULL;
  232.   thisdev = st.st_dev;
  233.   thisino = st.st_ino;
  234.  
  235.   if (__lstat ("/", &st) < 0)
  236.     return NULL;
  237.   rootdev = st.st_dev;
  238.   rootino = st.st_ino;
  239.  
  240.   dotsize = sizeof (dots) - 1;
  241.   dotp = &dots[sizeof (dots)];
  242.   dotlist = dots;
  243.   while (!(thisdev == rootdev && thisino == rootino))
  244.     {
  245.       register DIR *dirstream;
  246.       register struct dirent *d;
  247.       dev_t dotdev;
  248.       ino_t dotino;
  249.       char mount_point;
  250.  
  251.       /* Look at the parent directory.  */
  252.       if (dotp == dotlist)
  253.     {
  254.       /* My, what a deep directory tree you have, Grandma.  */
  255.       char *new;
  256.       if (dotlist == dots)
  257.         {
  258.           new = malloc (dotsize * 2 + 1);
  259.           if (new == NULL)
  260.         return NULL;
  261.           memcpy (new, dots, dotsize);
  262.         }
  263.       else
  264.         {
  265.           new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1);
  266.           if (new == NULL)
  267.         goto lose;
  268.         }
  269.       memcpy (&new[dotsize], new, dotsize);
  270.       dotp = &new[dotsize];
  271.       dotsize *= 2;
  272.       new[dotsize] = '\0';
  273.       dotlist = new;
  274.     }
  275.  
  276.       dotp -= 3;
  277.  
  278.       /* Figure out if this directory is a mount point.  */
  279.       if (__lstat (dotp, &st) < 0)
  280.     goto lose;
  281.       dotdev = st.st_dev;
  282.       dotino = st.st_ino;
  283.       mount_point = dotdev != thisdev;
  284.  
  285.       /* Search for the last directory.  */
  286.       dirstream = opendir (dotp);
  287.       if (dirstream == NULL)
  288.     goto lose;
  289.       while ((d = readdir (dirstream)) != NULL)
  290.     {
  291.       if (d->d_name[0] == '.' &&
  292.           (d->d_namlen == 1 || (d->d_namlen == 2 && d->d_name[1] == '.')))
  293.         continue;
  294.       if (mount_point || d->d_ino == thisino)
  295.         {
  296.           char *name = __alloca (dotlist + dotsize - dotp +
  297.                      1 + d->d_namlen + 1);
  298.           memcpy (name, dotp, dotlist + dotsize - dotp);
  299.           name[dotlist + dotsize - dotp] = '/';
  300.           memcpy (&name[dotlist + dotsize - dotp + 1],
  301.               d->d_name, d->d_namlen + 1);
  302.           if (__lstat (name, &st) < 0)
  303.         {
  304.           int save = errno;
  305.           (void) closedir (dirstream);
  306.           errno = save;
  307.           goto lose;
  308.         }
  309.           if (st.st_dev == thisdev && st.st_ino == thisino)
  310.         break;
  311.         }
  312.     }
  313.       if (d == NULL)
  314.     {
  315.       int save = errno;
  316.       (void) closedir (dirstream);
  317.       errno = save;
  318.       goto lose;
  319.     }
  320.       else
  321.     {
  322.       if (pathp - path < d->d_namlen + 1)
  323.         {
  324.           if (buf != NULL)
  325.         {
  326.           errno = ERANGE;
  327.           return NULL;
  328.         }
  329.           else
  330.         {
  331.           size *= 2;
  332.           buf = realloc (path, size);
  333.           if (buf == NULL)
  334.             {
  335.               (void) closedir (dirstream);
  336.               free (path);
  337.               errno = ENOMEM; /* closedir might have changed it.  */
  338.               return NULL;
  339.             }
  340.           pathp = &buf[pathp - path];
  341.           path = buf;
  342.         }
  343.         }
  344.       pathp -= d->d_namlen;
  345.       (void) memcpy (pathp, d->d_name, d->d_namlen);
  346.       *--pathp = '/';
  347.       (void) closedir (dirstream);
  348.     }
  349.  
  350.       thisdev = dotdev;
  351.       thisino = dotino;
  352.     }
  353.  
  354.   if (pathp == &path[size - 1])
  355.     *--pathp = '/';
  356.  
  357.   if (dotlist != dots)
  358.     free ((__ptr_t) dotlist);
  359.  
  360.   memmove (path, pathp, path + size - pathp);
  361.   return path;
  362.  
  363.  lose:
  364.   if (dotlist != dots)
  365.     free ((__ptr_t) dotlist);
  366.   return NULL;
  367. }
  368.